﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using KPIS.GERP.Models.HRM;
using KPIS.GERP.Models.SYS;
using KPIS.GERP.Models.SYS.ViewModel;
using System.Linq;
using KPIS.GERP.Models;
using KPIS.GERP.Models.Class;
using System.Data.Entity;

namespace KPIS.GERP.WCF.SYS
{
    public partial class SysApprovalService
    {
        public List<Task> SelectTask()
        {
            List<Task> result;
            using (var db = new GERPContext(false))
            {
                result = db.Tasks.Include(o=>o.TaskHistories).Where(o => o.RecordStatus != "D").ToList();
                foreach (var t in result)
                {
                    foreach (var th in t.TaskHistories)
                    {
                        th.Task = null;
                    }
                }
            }
            return result;
        }
        public CreateTaskVM CreateTask(CreateTaskVM model)
        { 
            OnWorkflowStartupInit(model); 

            // Create information of task 
            try
            {
                Task t = new Task();
                var db = new GERPContext(true);

                t.Remark = model.Remark;
                t.ApplyToEmpId = model.ApplyToEmpId;
                var calAppPrcIdVm = new CalAppPrcIdVm
                    {
                        AppPrcId = model.AppPrcId,
                        AppPrcGrpId = model.AppPrcGrpId,
                        Amount = model.Amount,
                        RefId = model.RefId,
                        CalculatedBaseOnEmpId = model.CreateByEmpId
                    };
                t.AppPrcId = FindAppPrcId(calAppPrcIdVm).AppPrcId;
                t.RefId = model.RefId;
                t.Amount = model.Amount;
                t.RefCode = model.RefCode;
                t.CreateResult = model.CreateResult;
                t.CreateErrorResult = model.CreateErrorResult;
                t.Remark = model.Remark;
                t.ConfirmAs = model.ConfirmAs;
                t.ApproveAs = model.ApproveAs;
                t.CreatedBy = model.CreateByEmpId;
                t.CreatedWhen = DateTime.Now;
                t.RecordStatus = "U";
                t.Title = model.Title;
                t.Code = CodeGenerate.GetNextCode(CodeGenerate.TransectionType.Task);
                model.TaskCode = t.Code;
                db.Tasks.Add(t);
                db.SaveChanges();
                OnWorkflowStartupLoad(model);

                model.TaskId = t.TaskId;

                // Create Simulate step, ขั้นตอนว่าต้องส่งไปหาใครบ้าง ถูกเจนเนอร์เรตตั้งแต่ตอนนี้
                db.SaveChanges();
                t.Simulates = LoadApprovePathSimulate(ref db, t.ApplyToEmpId, t.AppPrcId, false, model.RelatedToEmpId, model.CreateByEmpId); 
                foreach(var s in t.Simulates)
                {
                    s.ApproverPosition = db.Positions.FirstOrDefault(o => o.PosId == s.ApproverPosId);
                }

                // ด้วยปัญหาอะไรสักอย่าง เวลา Save แบบปกติ มันไม่เซฟเรียงตามลำดับใน Array ทำให้ได้ SimId เรียงสลับกับ StepNo, แก้ด้วยการ Add เข้าไปทีละตัว
                var simsTemp = t.Simulates;
                t.Simulates = new Collection<ApprovePathSimulate>();
                db.SaveChanges(); 
                foreach(var st in simsTemp.OrderBy(o=>o.SimulateStepNo))
                {
                    t.Simulates.Add(st);
                    db.SaveChanges();
                }
                // Update reference table record status as confirm as 
                // 1. Update ConfirmStatus;
                var ApproveProcess = db.ApproveProcesses.Find(t.AppPrcId);
                if (ApproveProcess.AppPrcGrpId == 1) // ขอลา ทั้งกลุ่ม Process ใช้วิธีนี้หมด
                {
                    db.PsAbsences.FirstOrDefault(o => o.AbsenceId == t.RefId).RecordStatus = t.ConfirmAs;
                }
                else if (ApproveProcess.AppPrcGrpId == 6) // คำขออนุมัติแจ้งความประสงค์
                {
                    db.PrePurchaseRequests.FirstOrDefault(o => o.PprId == t.RefId).RecordStatus = t.ConfirmAs;
                }
                else if (ApproveProcess.AppPrcGrpId == 7) // ขอเบิก
                {
                    db.RequestParcels.FirstOrDefault(o => o.ReqParcelId == t.RefId).RecordStatus = t.ConfirmAs;
                }
                else if (ApproveProcess.AppPrcGrpId == 8 // ขออนุมัติขอซื้อขอจ้างเกิน๑๐๐๐๐๐บาท
                         || ApproveProcess.AppPrcGrpId == 9) // ขออนุมัติขอซื้อขอจ้างไม่เกิน๑๐๐๐๐๐บาท
                {
                    db.PurchaseRequests.FirstOrDefault(o => o.PrId == t.RefId).RecordStatus = t.ConfirmAs;
                }
                else if (ApproveProcess.AppPrcGrpId == 10 // ขออนุมัติใบสั่งเกิน๑๐๐๐๐๐บาท
                         || ApproveProcess.AppPrcGrpId == 11 // ขออนุมัติใบสั่งไม่เกิน๑๐๐๐๐๐บาท
                         || ApproveProcess.AppPrcGrpId == 13) // ขออนุมัติงานสัญญา
                {
                    db.PurchaseOrders.FirstOrDefault(o => o.PoId == t.RefId).RecordStatus = t.ConfirmAs;
                }
                else if (ApproveProcess.AppPrcGrpId == 12) // ขออนุมัติประกาศ
                {
                    db.Bids.FirstOrDefault(o => o.BidId == t.RefId).RecordStatus = t.ConfirmAs;
                }
                else if (ApproveProcess.AppPrcGrpId == 14) // ตรวจรับ
                {
                    db.DeliveryNotes.FirstOrDefault(o => o.DnId == t.RefId).RecordStatus = t.ConfirmAs;
                }
                else if (ApproveProcess.AppPrcGrpId == 2) // คำสั่ง
                {
                    db.PsCommands.FirstOrDefault(o => o.CmdId == t.RefId).RecordStatus = t.ConfirmAs;
                }
                else if (ApproveProcess.AppPrcGrpId == 15) // รักษาการ
                {
                    db.MpPositionWorkOnDuties.FirstOrDefault(o => o.WodId == t.RefId).RecordStatus = t.ConfirmAs;
                }
                db.SaveChanges();

                // Go to step 1
                ActionTaskVM modelActionTaskVmStep1 = new ActionTaskVM();
                modelActionTaskVmStep1.ByEmpId = model.CreateByEmpId;
                modelActionTaskVmStep1.CommandAction = CommandAction.Initial;
                modelActionTaskVmStep1.NewTitle = model.Title;
                modelActionTaskVmStep1.Remarks = model.Remark;
                modelActionTaskVmStep1.TaskId = t.TaskId;

                ActionTask(modelActionTaskVmStep1);
                OnWorkflowStartupCompleted(model);
                return model;
            }
            catch (Exception ex)
            {
                model.CreateErrorResult += "Fatal error on SysApprovalService.svc.CreateTask or ActionTask  : " + ex.Message;
                if(ex.InnerException != null)
                {
                    model.CreateErrorResult += "{" + ex.InnerException.Message + "}";
                }if(ex.InnerException != null && ex.InnerException.InnerException != null)
                {
                    model.CreateErrorResult += "{" + ex.InnerException.InnerException.Message + "}";
                }
                model.CreateErrorResult = model.CreateErrorResult.Replace('\'', ' ').Replace('"', ' ');
                OnWorkflowFailed(model.TaskId, model, null, model.CreateErrorResult);
                return model;
            }
        }

        public ActionTaskVM ActionTask(ActionTaskVM model)
        {
            OnWorkflowEscalateStart(ref model);
            if(!string.IsNullOrWhiteSpace(model.CommandActionErrorResult))
            {
                return model;
            }

            // This method can Take Action to the Initilizing task and escalating task.
            // Load employee object (for send back to client)
            using (var dbNoProxy = new GERPContext(false))
            {
                model.ByEmployee = dbNoProxy.Employees.Include(o => o.Position).First(o => o.EmpId == model.ByEmpId);
                 
            }

            var db = new GERPContext(true);
            {
                Task t;
                ApprovePathSimulate newSim = null;

                // Load #1: task

                model.TaskId = model.TaskId.HasValue ?
                    model.TaskId :
                    db.TaskHistories.First(o => o.TaskHistoryId == model.TaskHistoryId).TaskId;

                t = db.Tasks
                    .Include(o => o.Simulates)
                    .Include(o => o.TaskHistories)
                    .Include(o => o.CurrentTaskHistory)
                    .Include(o => o.ApproveProcess.ApproveProcessGroup)
                    .Include(o => o.CreateByEmployee)
                    .FirstOrDefault(o => o.TaskId == model.TaskId);

                // Validate #1: it's must not completed
                if (t.Completed)
                {
                    model.Remarks = model.CommandActionErrorResult = "คำขอสิ้นสุดแล้ว ไม่สามารถกระทำการใดๆ ได้";
                    OnWorkflowEscalateComplete(model);
                    return model;
                }

                // Validate #2: taskHistory must be valid
                if (model.CommandAction != CommandAction.Initial)
                {
                    TaskHistory fromTh = db.TaskHistories.FirstOrDefault(o => o.TaskHistoryId == model.TaskHistoryId);
                    if (!model.TaskHistoryId.HasValue || fromTh == null || t.CurrentTaskHistoryId != model.TaskHistoryId || t.CurrentTaskHistory.PassStep)
                    {
                        string message = string.Format("คำสั่งนี้ไม่ถูกต้อง อาจเพราะขั้นตอนปัจจุบันของคำขอ ถูกเปลี่ยนไปแล้ว {0}", (t.CurrentTaskHistory.PassStep ? "โดย" + t.CurrentTaskHistory.ActionByFullName : string.Empty));
                        model.Remarks = model.CommandActionErrorResult = message;
                        OnWorkflowEscalateComplete(model);
                        return model;
                    }
                }

                // DoWork #1: update some info of Task
                t.Title = model.NewTitle;
                t.UpdatedBy = model.ByEmpId;
                t.UpdatedWhen = DateTime.Now;

                // DoWork #2: 
                // - update message send status as Actioned (message_send that bring user to here)
                // - create message reply (use for which action he decide (approve , forward, reject)
                //   CASE WHEN re.reply_type = '0' THEN 'ส่งกลับ'
                //             ELSE CASE WHEN re.reply_type = '1' THEN 'อนุมัติ'
                //                 ELSE CASE WHEN re.reply_type = '2' THEN 'ส่งต่อ'
                //                     ELSE CASE WHEN send.message_status = '2' THEN 'ส่งต่อ'
                //                         ELSE 'รอการพิจารณา'
                //                         END
                //                     END
                //                 END
                //             END AS reply_type_name
                MessageSend ms = db.MessageSends.FirstOrDefault(o => o.RefType == "sys_task" && o.RecordStatus != "D" && o.RefId == t.CurrentTaskHistoryId);
                MessageReply mr = null;
                if (ms != null)
                {
                    // Message Status 2 mean that message_send got some action
                    ms.MessageStatus = "2";
                    ms.WodEmpId = model.ByEmpId == ms.ToEmpId ? (int?)null : model.ByEmpId; 
                    ms.UpdatedBy = model.ByEmpId;
                    ms.UpdatedWhen = DateTime.Now;

                    // Message Reply Create
                    mr = new MessageReply();
                    mr.ReplyDate = DateTime.Now;
                    mr.RefNo = ms.RefNo;
                    switch (model.CommandAction)
                    {
                        // โดยระบบ
                        // Initial = 0, // เพิ่งเริ่ม

                        // โดยผู้บังคับบัญชา
        
                        case CommandAction.Approve: mr.ReplyType = "1";break; // อนุมัติ
        
                        case CommandAction.Forward: mr.ReplyType = "2"; break; // ส่งต่อไปขั้นตอนข้างหน้า 1 ขั้นตอน (ไม่ให้เลือก เว้นแต่ขั้นตอนนี้ผู้อนุมัติเป็น JobSite หรือ Team)
        
                        case CommandAction.Reject: mr.ReplyType = "3"; break; // ไม่ผ่านการอนุมัติ ข้อความจะไม่ผ่านการอนุมตไปทางสายที่ผ่านมาแต่ละขั้นตอนทุกคน (Optional) ไม่สามารถนำคำขอเดิมกลับมาใช้ได้อีก
        
                        // case CommandAction.Pending: mr.ReplyType = "1";break; // พักคำขอ (โดย ผู้อนุมัติ)
        
                        //case CommandAction.Information: mr.ReplyType = "1";break; // ขั้นตอนเพื่อส่งข้อความอย่างเดียว
        
                        case CommandAction.SendBack: mr.ReplyType = "0"; break; // ส่งกลับ พร้อมเหตุผล และ

                        // โดยผู้ดูแลระบบ
                        //Lock = 7, // หยุดคำขอ (โดย ระบบ หรือ Admin)
                        // และ Cancel = 8, // ยกเลิกคำขอ (โดยผู้ขอ - ทำระหว่างขออนุมัติ)

                        // โดยผู้ขอ ผู้ดูแลระบบ
        
                        case CommandAction.Cancel: mr.ReplyType = "4"; break; // ยกเลิกคำขอ (โดยผู้ขอ - ทำระหว่างขออนุมัติ)
        
                        //case CommandAction.SendBackOk: mr.ReplyType = "1";break; // ส่งคืน ส่งกลับผู้อนุมัติคนเดิม

                        // โดยสายบังคับบัญชา และผู้ขอ และหัวหน้าสูงสุด
        
                        //case CommandAction.TakeBack: mr.ReplyType = "1";break; 
                    }
                    mr.ReplyText = model.NewTitle;
                    mr.FromEmpId = model.ByEmpId;
                    mr.FromPosId = model.ByEmployee.PosId;
                    mr.ToEmpId = null;
                    mr.ToPosId = null;
                    mr.WodEmpId = model.ByEmpId == ms.ToEmpId ? (int?)null : model.ByEmpId;
                    mr.FromSendId = ms.SendId;
                    mr.Remarks = model.Remarks;
                    mr.MessageStatus = "0";
                    mr.RecordStatus = "U";
                    mr.CreatedBy = model.ByEmpId;
                    mr.CreatedWhen = DateTime.Now;
                    db.MessageReplys.Add(mr);
                    db.SaveChanges();
                }

                // Do work #3: update currentTaskHistory information
                if (model.CommandAction != CommandAction.Initial &&
                    t.CurrentTaskHistory.UpdateFieldByCommandAction(
                        model.CommandAction,
                        model.ByEmpId,
                        model.ByEmployee.FullName,
                        Convert.ToString(model.ByEmployee.Position.PosNo),
                        model.ByEmployee.Position.Name,
                        model.Remarks))
                {

                    // Complete when resultIsCompleted = true
                    db.SaveChanges();
                    OnWorkflowEscalateComplete(model);
                    OnWorkflowComplete(model);
                    return model;
                }
                
                /*
                if (model.CommandAction == CommandAction.SendBack)
                {
                    // you need to remove after current step 
                    var moreSim = LoadApprovePathSimulate(ref db, t.ApplyToEmpId, t.AppPrcId, false, null, t.CreatedBy);
                    int maxStep1 = t.Simulates.Max(o => o.SimulateStepNo);
                    foreach(var s in moreSim)
                    {
                        s.SimulateStepNo += maxStep1;
                        t.Simulates.Add(s);
                    }
                }*/
                // DoWork #4: if send back, mark flag as IsInRequiringSendBack
                if (model.CommandAction == CommandAction.SendBack)
                {
                    // waiting sendback reply
                    t.IsInRequiringSendBack = true;

                    // current task history is now complete, create the waiting send back reply task history
                    TaskHistory nextTh = new TaskHistory();
                    nextTh.SimId = t.CurrentTaskHistory.SimId;
                    nextTh.ApproverType = ApproverType.WaitRequesterSendBack;
                    nextTh.ApproverTypeText = ApproverType.WaitRequesterSendBack.ToString();
                    nextTh.ApproverPosId = t.CreateByEmployee.PosId;
                    nextTh.IsApproveAble = false;
                    nextTh.IsForwardable = false;
                    nextTh.IsRejectable = false;
                    nextTh.IsPendable = false;
                    nextTh.IsSendBackable = false;
                    nextTh.IsInRequiringSendBack = true;
                    nextTh.StepNo = (t.CurrentTaskHistory.StepNo ?? 0) + 1;
                    nextTh.RecordStatus = "U";
                    nextTh.CreatedBy = model.ByEmpId;
                    nextTh.CreatedWhen = DateTime.Now;
                    nextTh.TaskId = t.TaskId;
                    nextTh.FromTaskHistoryId = t.CurrentTaskHistoryId;
                    nextTh.PassStep = false;
                    nextTh.ResultStep = null;
                    nextTh.Remark = null;
                    nextTh.SystemRemark = null;
                    db.TaskHistories.Add(nextTh);
                    db.SaveChanges();
                    t.CurrentTaskHistoryId = nextTh.TaskHistoryId;
                    Employee nextApprover = db.Employees.FirstOrDefault(o => o.PosId == nextTh.ApproverPosId && o.RecordStatus != "D");
                    if(mr != null) mr.ToEmpId = nextApprover != null ? (int?)nextApprover.EmpId : null;
                    db.SaveChanges();
                     
                    SendMessageSend(t.CurrentTaskHistory.TaskHistoryId, t.RefCode, model.NewTitle, model.ByEmpId, model.ByEmployee.PosId.Value,
                        t.CreatedBy.Value, t.CreateByEmployee.PosId.Value, model.Remarks);
                    db.SaveChanges();

                    OnWorkflowSendBack(t.TaskId);
                    db.SaveChanges();
                    OnWorkflowEscalateComplete(model);
                    return model;
                }
                else if (model.CommandAction == CommandAction.SendBackOk)
                {
                    t.IsInRequiringSendBack = false;
                    newSim = db.ApprovePathSimulates.Find(t.CurrentTaskHistory.SimId);
                    // current task history is now complete, create the waiting send back reply task history
                    TaskHistory nextTh = new TaskHistory();
                    nextTh.SimId = t.CurrentTaskHistory.SimId; 
                    nextTh.ApproverType = newSim.ApproverType;
                    nextTh.ApproverTypeText = newSim.ApproverType.ToString();
                    nextTh.ApproverPosId = newSim.ApproverPosId;
                    nextTh.IsApproveAble = newSim.IsApproveAble;
                    nextTh.IsForwardable = newSim.IsForwardable;
                    nextTh.IsRejectable = newSim.IsRejectable;
                    nextTh.IsSendBackable = newSim.IsSendBackable;
                    nextTh.StepNo = (t.CurrentTaskHistory.StepNo ?? 0) + 1;
                    nextTh.CreatedBy = model.ByEmpId;
                    nextTh.CreatedWhen = DateTime.Now;
                    nextTh.FromTaskHistoryId = t.CurrentTaskHistoryId;
                    nextTh.RecordStatus = "U";
                    nextTh.TaskId = t.TaskId;
                    nextTh.SimId = newSim.SimId;
                    t.TaskHistories.Add(nextTh);

                    db.TaskHistories.Add(nextTh);
                    Employee nextApprover = db.Employees.FirstOrDefault(o => o.PosId == nextTh.ApproverPosId && o.RecordStatus != "D");
                    if(mr != null) mr.ToEmpId = nextApprover != null ? (int?)nextApprover.EmpId : null;
                    db.SaveChanges();
                    t.CurrentTaskHistoryId = nextTh.TaskHistoryId;
                    db.SaveChanges();
                    var nextApproverEmpId = (from e in db.Employees where e.RecordStatus != "D" && e.PosId == newSim.ApproverPosId select (int?)e.EmpId).FirstOrDefault();
                    SendMessageSend(t.CurrentTaskHistory.TaskHistoryId, t.RefCode, model.NewTitle, model.ByEmpId, model.ByEmployee.PosId.Value,
                        nextApproverEmpId, newSim.ApproverPosId, model.Remarks);
                    db.SaveChanges();

                    OnWorkflowEscalateComplete(model);
                    OnWorkflowSendBackReturn(t.TaskId);
                    return model;
                }
                else
                {

                }

                // Validate #3: NewSim (next simulate) must be valid
                int nextStep;
                if (model.CommandAction == CommandAction.Initial)
                {
                    // ขั้นตอนเริ่มต้น 
                    nextStep = 1;
                }
                else
                {
                    // ขั้นตอนถัดไป คือ ปัจจุบัน + 1
                    int currentSimId = t.CurrentTaskHistory.SimId.Value;
                    int currentStepOfSimId = t.CurrentTaskHistory.ApprovePathSimulate.SimulateStepNo;
                    nextStep = currentStepOfSimId + 1;
                }

                // ขั้นตอนที่ยังไม่ถึง คือ ตัวเลขขั้นตอน มากกว่า หรือ เท่ากับ เลขขั้นตอนถัดไปที่กำลังจะโหลด (nextStep) และไม่ใช่ขั้นตอนที่ข้ามได้
                var futureSim = t.Simulates.OrderBy(o => o.SimulateStepNo).Where(o => o.SimulateStepNo >= nextStep);
                // ขั้นตอนสูงสุดที่มี
                int maxStep = futureSim.Select(fs => fs.SimulateStepNo).Concat(new[]
                    {
                        0
                    }).Max();
                // หาขั้นตอนถัดไป หาก ปัจจุบันคือ 3 หาไม่เจอก็ไป 4 ไป 5 จนกว่าจะเจอ ผลใน task history อาจได้เลข StepNo เป็น 1->2->5 เลยก็ได้
                while ((newSim = futureSim.FirstOrDefault(o => o.SimulateStepNo == nextStep)) == null
                       && nextStep <= maxStep)
                {
                    nextStep++;
                }

                // หาขั้นตอนต่อไปไม่เจอ ให้จบโฟล์
                if (newSim == null)
                { 
                    // Complete
                    db.SaveChanges();
                    OnWorkflowEscalateComplete(model);
                    OnWorkflowComplete(model);
                    return model;
                }

                // DoWork #5: go to next simulate, create new TaskHistory copy info from next Simulate.
                TaskHistory nextTh2 = new TaskHistory();
                nextTh2.ApproverType = newSim.ApproverType;
                nextTh2.ApproverTypeText = newSim.ApproverType.ToString();
                nextTh2.ApproverPosId = newSim.ApproverPosId;
                nextTh2.IsApproveAble = newSim.IsApproveAble;
                nextTh2.IsForwardable = newSim.IsForwardable;
                nextTh2.IsRejectable = newSim.IsRejectable;
                nextTh2.IsSendBackable = newSim.IsSendBackable;
                nextTh2.StepNo = model.CommandAction == CommandAction.Initial ? 1 : (t.CurrentTaskHistory.StepNo ?? 0) + 1;
                nextTh2.CreatedBy = model.ByEmpId;
                nextTh2.CreatedWhen = DateTime.Now;
                nextTh2.FromTaskHistoryId = t.CurrentTaskHistoryId;
                nextTh2.RecordStatus = "U";
                nextTh2.TaskId = t.TaskId;
                nextTh2.SimId = newSim.SimId;
                t.TaskHistories.Add(nextTh2);
                db.SaveChanges();
                t.CurrentTaskHistoryId = nextTh2.TaskHistoryId;
                db.SaveChanges();

                // DoWork #6: send new message_send
                var nextApproverEmpId1 = (from e in db.Employees where e.RecordStatus != "D" && e.PosId == newSim.ApproverPosId select (int?)e.EmpId).FirstOrDefault();
                 
                var messageTitle = t.ApproveProcess.ApproveProcessGroup.Name + ":" + t.Title;
                SendMessageSend(nextTh2.TaskHistoryId, t.RefCode, messageTitle, model.ByEmpId, model.ByEmployee.PosId.Value,
                                nextApproverEmpId1, newSim.ApproverPosId, nextTh2.Remark);
                db.SaveChanges(); 
            }
            OnWorkflowEscalateComplete(model);
            return model;
        }

        public class VM1
        {
            public MessageSend MessageSend { get; set; }
            public MessageReply MessageReply { get; set; }
            public TaskHistory TaskHistory { get; set; }
            public Task Task { get; set; }
        }

        public string InsertMessageReplyWhichNoReplyButCompleted()
        {
            string result = "";
            using(var db = new GERPContext(true))
            {
                var q = from s in db.MessageSends
                        from r in db.MessageReplys.Where(mapping=>mapping.FromSendId == s.SendId).DefaultIfEmpty()
                        from h in db.TaskHistories.Where(mapping=>mapping.TaskHistoryId == s.RefId) .DefaultIfEmpty()
                        from t in db.Tasks.Where(mapping=>mapping.TaskId == h.TaskId) .DefaultIfEmpty()
                        where s.MessageStatus == "2" && s.RefType == "sys_task" &&
                        h.ActionCode != null
                        select new VM1{MessageSend = s, MessageReply = r, TaskHistory = h, Task = t};
                var countQ = q.ToList().Count();
                var mss = db.MessageSends.ToList();
                foreach(var s in q)
                {
                    MessageReply r = new MessageReply();
                    r.ReplyDate = s.TaskHistory.CreatedWhen;
                    r.RefNo = s.MessageSend.RefNo;
                    switch (s.TaskHistory.ActionCode.ToLower())
                    {
                        case "approve":
                            r.ReplyText = "อนุมัติ";
                            break;
                        case "cancel":
                            r.ReplyText = "ยกเลิก";
                            break;
                        case "forward":
                            r.ReplyText = "ส่งต่อ";
                            break;
                        case "reject":
                            r.ReplyText = "ไม่ผ่านการอนุมัติ";
                            break;
                        case "rendback":
                        case "rendbackok":
                            r.ReplyText = "ส่งกลับให้แก้ไข";
                            break;
                    }
                    r.ReplyText +=  " : " + s.MessageSend.SendText;
                    r.FromEmpId = s.TaskHistory.ActionBy;
                    bool foundCurrent = false;
                    MessageSend msNext = null;
                    foreach(var s2 in mss.Where(o => o.RefType == "sys_task" && o.RefId == s.Task.TaskId).ToList())
                    {
                        if(foundCurrent)
                        {
                            msNext = s2;
                            break;
                        } else if(s2.SendId == s.MessageSend.SendId)
                        {
                            foundCurrent = true;
                        }
                    }
                    r.ToEmpId = msNext != null ? msNext.ToEmpId : null;
                    r.FromSendId = s.MessageSend.SendId;
                    r.Remarks = s.TaskHistory.Remark;
                    r.MessageStatus = "0";
                    r.RecordStatus = "U";
                    r.CreatedBy = s.TaskHistory.ActionBy;
                    if(s.TaskHistory.ApprovedWhen.HasValue)
                    {
                        r.CreatedWhen = s.TaskHistory.ApprovedWhen;
                    } else if(s.TaskHistory.CanceledWhen.HasValue)
                    {
                        r.CreatedWhen = s.TaskHistory.CanceledWhen;
                    }else if(s.TaskHistory.CreatedWhen.HasValue)
                    {
                        r.CreatedWhen = s.TaskHistory.CreatedWhen;
                    }else if(s.TaskHistory.ForwardWhen.HasValue)
                    {
                        r.CreatedWhen = s.TaskHistory.ForwardWhen;
                    }else if(s.TaskHistory.RejectedWhen.HasValue)
                    {
                        r.CreatedWhen = s.TaskHistory.RejectedWhen;
                    }else if(s.TaskHistory.SendBackOkWhen.HasValue)
                    {
                        r.CreatedWhen = s.TaskHistory.SendBackOkWhen;
                    }else if(s.TaskHistory.SendBackWhen.HasValue)
                    {
                        r.CreatedWhen = s.TaskHistory.SendBackWhen;
                    }else if(s.TaskHistory.UpdatedWhen.HasValue)
                    {
                        r.CreatedWhen = s.TaskHistory.UpdatedWhen;
                    }else if(s.TaskHistory.CreatedWhen.HasValue)
                    {
                        r.CreatedWhen = s.TaskHistory.CreatedWhen;
                    }else
                    {
                        r.CreatedWhen = DateTime.Now;
                    }
                    switch (s.TaskHistory.ActionCode)
                    {
                        case "Approve":
                            r.ReplyType = "1";
                            break;
                        case "Cancel":
                            r.ReplyType = "4";
                            break;
                        case "Reject":
                            r.ReplyType = "3";
                            break;
                        case "Forward":
                            r.ReplyType = "2";
                            break;
                        default:
                            r.Remarks += s.TaskHistory.ActionCode;
                            break;
                    }
                    result += "inserted reply (" + db.MessageReplys.Add(r) + ") by send_seq (" + s.MessageSend.SendId +
                              ") Action Code = " + s.TaskHistory.ActionCode + ", reply_type = " + r.ReplyType + "\r\n";
                }
                db.SaveChanges();
                return result;
            }
        }

        public string CheckSimulateWrongOrdering()
        {
            string result = "";
            using(var db = new GERPContext(true))
            {
                foreach(var t in db.Tasks.Include(o=>o.Simulates))
                {  
                    int stepno = 0;
                    foreach(var s in t.Simulates.OrderBy(o=>o.SimId))
                    {
                        if(s.SimulateStepNo < stepno)
                        {
                            result += "TaskId[" + t.TaskId + "], SimId[" + s.SimId + "], Step[" + s.SimulateStepNo + "]\r\n";
                        }
                        stepno = s.SimulateStepNo;
                    }
                }
            }
            return result;
        }
    }
}